package com.gonsin.gmessage.logic.utils;

import com.gonsin.gmessage.annotations.GArgsParam;
import com.gonsin.gmessage.logic.exceptions.GMessageException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.springframework.util.CollectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;

@Slf4j
public class ClassUtil {

    private static List<String> BASE_TYPE = Arrays.asList(
            "int", "byte", "boolean", "double", "float", "short", "char", "long",
            String.class.getName(),
            Integer.class.getName(),
            Byte.class.getName(),
            Boolean.class.getName(),
            Double.class.getName(),
            Float.class.getName(),
            Short.class.getName(),
            Character.class.getName(),
            Long.class.getName()
    );

    private static List<String> BASE_ARRAY_TYPE = Arrays.asList(
            short[].class.getName(),
            long[].class.getName(),
            char[].class.getName(),
            int[].class.getName(),
            byte[].class.getName(),
            boolean[].class.getName(),
            double[].class.getName(),
            float[].class.getName(),
            String[].class.getName(),
            Integer[].class.getName(),
            Byte[].class.getName(),
            Boolean[].class.getName(),
            Double[].class.getName(),
            Float[].class.getName(),
            Short[].class.getName(),
            Character[].class.getName(),
            Long[].class.getName()
    );

    /**
     * 获取当前类以及所有父类的成员变量。
     */
    public static List<Field> getAllFields(Class clazz){
        List<Field> all = new ArrayList<>();
        all.addAll(Arrays.asList(clazz.getDeclaredFields()));
        Class superClazz = clazz.getSuperclass();
        if(superClazz != null){
            List<Field> subFields = getAllFields(superClazz);
            if(CollectionUtils.isEmpty(subFields)){
                return all;
            }
            all.addAll(subFields);
        }
        return all;
    }

    public static boolean isBasicClass(Class clz) {
        try {
            if(BASE_TYPE.contains(clz.getName())){
                return true;
            }
            return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 是否为基本类型数组
     */
    public static boolean isBasicArrayClass(Class clz) {
        try {
            if(BASE_ARRAY_TYPE.contains(clz.getName())){
                return true;
            }
        } catch (Exception e) {
        }
        return false;
    }


    /**
     * 方法中是否包含GSession
     */
    public static <T> T searchParamAnnotation(Method method, int index, Class<? extends Annotation> annotationType) {
        Annotation[] annotations = method.getParameterAnnotations()[index];
        for(int i = 0; i < annotations.length; i++){
            if(annotationType.isAssignableFrom(annotations[i].getClass())){
                return (T) annotations[i];
            }
        }
        return null;
    }


    public static <T> T map2Object(Map<String, Object> props, Class<?> clazz){

        // TODO 通过转json作为中间过渡，不太确定会不会有什么问题，先试一下看看。
        Gson gson = new Gson();
        String json = gson.toJson(props);
        return (T) gson.fromJson(json, clazz);

//        Object searchPo = null;
//        try {
//            searchPo = clazz.newInstance();
//        } catch (Exception e) {
//            log.error(e.toString(), e);
//            throw new GMessageException(String.format("无法创建类【%s】", clazz.getName()));
//        }
////        Map<String, Object> searchPoMap = new HashMap<>();
////        Field[] allFields = clazz.getDeclaredFields();
////        for(Field field : allFields){
////            try {
////                if(isBasicClass(field.getType()) && !Date.class.isAssignableFrom(field.getType())){
////
////                }
////                searchPoMap.put(field.getName(), ValueUtils.parseValue(props.get(field.getName()), field.getGenericType()));
////            } catch (Exception ex) {
////                log.warn(ex.toString(), ex);
////                log.warn("设置参数【{}】，设置的内容为“{}“", field.getName(), props.get(field.getName()));
////            }
////        }
//        try {
//            BeanUtilsBean utils = BeanUtilsBean.getInstance();
//
//
//
//            // 非基本类型转换时，使用特殊方法
//            Field[] allFields = clazz.getDeclaredFields();
//            for(Field field : allFields){
//                try {
//                    if(!isBasicClass(field.getType()) && !Date.class.isAssignableFrom(field.getType())){
//                        utils.getConvertUtils().register(new CommonClassConverter(field.getType()), field.getType());
//                    }
//                } catch (Exception ex) {
//                    log.warn(ex.toString(), ex);
//                    log.warn("设置参数【{}】，设置的内容为“{}“", field.getName(), props.get(field.getName()));
//                }
//            }
//
//            utils.getConvertUtils().register(new MyDateConverter(), java.util.Date.class);
//            utils.getConvertUtils().register(new MyBooleanConverter(), Boolean.class);
//            utils.getConvertUtils().register(new MyIntegerConverter(), Integer.class);
//            utils.getConvertUtils().register(new MyLongConverter(), Long.class);
//            utils.getConvertUtils().register(new MyShortConverter(), Short.class);
//            utils.getConvertUtils().register(new MyByteConverter(), Byte.class);
//            utils.getConvertUtils().register(new MyDoubleConverter(), Double.class);
//            utils.getConvertUtils().register(new MyFloatConverter(), Float.class);
//            utils.getConvertUtils().register(new MyCharConverter(), Character.class);
//
//
//
//            utils.populate(searchPo, props);
//            return (T) searchPo;
//        } catch (Exception e) {
//            log.error(e.toString() ,e);
//            throw new GMessageException(String.format("无法创建类【%s】", clazz.getTypeName()));
//        }
    }



    /**
     * 獲取參數名字
     */
    public static String getParamName(Method method, int i) {
        Annotation[] param = method.getParameterAnnotations()[i];
        if(param == null){
            return method.getParameters()[i].getName();
        }
        for(Annotation annotation : param){
            if(annotation instanceof GArgsParam){
                return ((GArgsParam) annotation).value();
            }
        }
        return method.getParameters()[i].getName();
    }



    /**
     * TODO 将字符串转化成任意类型
     */
    public static <T> T parseValue(Object obj, Type type) {
        if(obj == null){
            return null;
        }
        String value = (obj instanceof String) ? (String) obj : obj.toString();
        if(value == null){
            return null;
        }
        if(type.equals(String.class)){
            return (T) value;
        }
        if(value.equals("")){
            return null;
        }
        if(Integer.class == type){
            return (T) Integer.class.cast(Double.valueOf(value).intValue());
        }
        if(Long.class == type){
            return (T) Long.class.cast(Double.valueOf(value).longValue());
        }
        if(String.class == type){
            return (T) value;
        }
        if(Boolean.class == type){
            return (T) (Boolean.valueOf("true".equalsIgnoreCase(value)));
        }
        if(Float.class == type){
            return (T)Float.valueOf(value);
        }
        if(Double.class == type){
            return (T)Double.valueOf(value);
        }
        if(Byte.class == type){
            return (T) Byte.class.cast(Float.valueOf(value).byteValue());
        }
        if(Short.class == type){
            return (T) Short.class.cast(Float.valueOf(value).shortValue());
        }
        if(Character.class == type){
            return (T)Character.valueOf(value.toCharArray()[0]);
        }
        Gson gson = new GsonBuilder()
                .enableComplexMapKeySerialization()
                .disableHtmlEscaping().create();
        Object map = gson.fromJson(value, type);
        return (T) map;
    }


    /**
     * 转换到目标类型
     */
    public static Object convertToTargetType(Object origin, Class targetClass) {
        if(origin == null){
            return null;
        }
        Class originClass = origin.getClass();

        // 如果是基本类型之间的转换
        if(isBasicClass(originClass) && isBasicClass(targetClass)) {
            String originString = origin.toString();
            return parseValue(originString, targetClass);
        }


        // 如果是map 和对象之间的转换
        if(origin instanceof Map && !isBasicClass(targetClass)){
            try {
                Map<String, Object> originMap = (Map<String, Object>) origin;
                return map2Object(originMap, targetClass);
            } catch (Exception ex) {

            }
        }

        log.warn("不支持从【{}】到【{}】的类型转换", origin.getClass().getName(), targetClass.getName());
        return null;
    }
}
